package cool.webstudy.admin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import cool.webstudy.admin.constant.enums.CompetitionQuestionStatusEnum;
import cool.webstudy.admin.constant.enums.CompetitionStatusEnum;
import cool.webstudy.admin.constant.enums.DelFlagEnum;
import cool.webstudy.admin.constant.enums.rescode.CompetitionResCodeEnum;
import cool.webstudy.admin.constant.enums.rescode.CompetitionTeamResCodeEnum;
import cool.webstudy.admin.constant.enums.rescode.docker.ImageResCodeEnum;
import cool.webstudy.admin.exception.BusinessException;
import cool.webstudy.admin.mapper.competition.CompetitionMapper;
import cool.webstudy.admin.model.dto.competition.*;
import cool.webstudy.admin.model.dto.competition.question.QueryCompetitionQuestionDetailInfoDTO;
import cool.webstudy.admin.model.dto.competition.team.CreateCompetitionTeamDTO;
import cool.webstudy.admin.model.dto.competition.team.UpdateCompTeamLoginInfoDTO;
import cool.webstudy.admin.model.dto.docker.container.ContainerIdAndNameMapInfoDTO;
import cool.webstudy.admin.model.dto.docker.container.ContainerNetworkInfoDTO;
import cool.webstudy.admin.model.dto.scheduler.CompetitionStartSchedulerTaskDTO;
import cool.webstudy.admin.model.dto.scheduler.CreateSchedulerTaskDTO;
import cool.webstudy.admin.model.dto.user.UserDetailInfoDTO;
import cool.webstudy.admin.model.po.BaseModel;
import cool.webstudy.admin.model.po.competition.CompetitionPO;
import cool.webstudy.admin.model.vo.competition.PaginationQueryCompetitionInfoListVO;
import cool.webstudy.admin.model.vo.competition.QueryCompetitionDetailInfoVO;
import cool.webstudy.admin.model.vo.competition.QueryCompetitionRoughInfoVO;
import cool.webstudy.admin.service.CompetitionQuestionService;
import cool.webstudy.admin.service.CompetitionService;
import cool.webstudy.admin.service.CompetitionTeamService;
import cool.webstudy.admin.service.ISchedulerTaskService;
import cool.webstudy.admin.service.callback.CallBack;
import cool.webstudy.admin.service.docker.ContainerService;
import cool.webstudy.admin.service.docker.ImageService;
import cool.webstudy.admin.service.impl.callback.CompetitionChangeStatusCallBack;
import cool.webstudy.admin.utils.CornUtil;
import cool.webstudy.admin.utils.IPUtil;
import cool.webstudy.admin.utils.TimeUtil;
import cool.webstudy.admin.utils.UserDetailUtil;
import cool.webstudy.common.constant.enums.EnabledStatusFlagEnum;
import cool.webstudy.common.utils.UUIDUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 莫振双
 * @date 2025/1/18 16:14
 * @description: 赛事服务实现类
 */
@Slf4j
@Service
public class CompetitionServiceImpl implements CompetitionService {
    @Autowired
    private CompetitionMapper competitionMapper;
    @Autowired
    private ContainerService containerService;
    @Autowired
    private ImageService imageService;
    @Autowired
    private CompetitionTeamService competitionTeamService;
    @Autowired
    private CompetitionQuestionService competitionQuestionService;
    @Autowired
    private ISchedulerTaskService schedulerTaskService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void initForIP(InitCompetitionForIPDTO dto) {
        //判断是否有队伍已经参加过该场赛事，如果有，则不允许初始化，提示重新创建新的赛事
        Boolean isExistRecord = competitionTeamService.isExistRecord(dto.getUnCode(), dto.getTeamUnCodes());
        if (isExistRecord) {
            throw new BusinessException(CompetitionTeamResCodeEnum.RC_ERROR_EXIST_RECORD);
        }
        //判断IP数量与队伍数量是否匹配
        List<String> ipList = IPUtil.generateIpList(dto.getStartIpAddress(), dto.getEndIpAddress(), true);
        if (ipList.size() != dto.getTeamUnCodes().length) {
            throw new BusinessException(CompetitionResCodeEnum.RC_ERROR_IP_TEAM_MISMATCH);
        }
        //判断是否有其他赛事进行
        LambdaQueryWrapper<CompetitionPO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CompetitionPO::getStatusFlag, CompetitionStatusEnum.IN_THE_COMP);
        if (!competitionMapper.selectList(queryWrapper).isEmpty()) {
            throw new BusinessException(CompetitionResCodeEnum.RC_ERROR_IN_THE_COMP);
        }
        //查询赛事信息，并判断赛事开始时间是否是当天，目前设定只有比赛当天才能初始化比赛
        QueryCompetitionDetailInfoDTO queryCompetitionDetailInfo = queryCompetitionDetailInfo(dto.getUnCode());
        Date startTime = queryCompetitionDetailInfo.getStartTime();
        if (!TimeUtil.isToday(startTime)) {
            throw new BusinessException(CompetitionResCodeEnum.RC_ERROR_COMP_NOT_TODAY);
        }
        //更新赛事状态为初始化中
        updateCompetitionStatus(dto.getUnCode(), CompetitionStatusEnum.INITIALIZING);
        //镜像信息
        String imageInfo = "nickistre/ubuntu-lamp:latest";
        //查询镜像是否存在
        Boolean isExistImage = imageService.isExistImage(imageInfo);
        if (!isExistImage){
            throw new BusinessException(ImageResCodeEnum.RC_ERROR_NOT_EXIST, imageInfo);
        }
        //容器信息
        String[] containerNames = dto.getTeamUnCodes();
        //批量创建容器
        Map<String, ContainerNetworkInfoDTO> containerNetworkInfoMap = containerService.batchCreateContainer(imageInfo, containerNames, dto.getStartIpAddress(), dto.getEndIpAddress());
        List<String> containerIdList = new ArrayList<>();
        //创建赛事、队伍与容器之间的对应关系记录
        List<CreateCompetitionTeamDTO> createCompetitionTeamDTOList = new ArrayList<>();
        containerNetworkInfoMap.forEach((key, value) -> {
            ContainerNetworkInfoDTO containerNetworkInfoDTO = containerNetworkInfoMap.get(key);
            CreateCompetitionTeamDTO createCompetitionTeamDTO = new CreateCompetitionTeamDTO();
            createCompetitionTeamDTO.setCompUnCode(dto.getUnCode());
            createCompetitionTeamDTO.setTeamUnCode(key);
            createCompetitionTeamDTO.setContainerId(containerNetworkInfoDTO.getId());
            createCompetitionTeamDTO.setCurrentScore(queryCompetitionDetailInfo.getInitialTotalScore());
            createCompetitionTeamDTO.setTeamNetAddress(containerNetworkInfoDTO.getNetAddress());
            createCompetitionTeamDTO.setTeamNetPort(containerNetworkInfoDTO.getNetPort());
            createCompetitionTeamDTOList.add(createCompetitionTeamDTO);
            containerIdList.add(containerNetworkInfoDTO.getId());
        });
        competitionTeamService.batchCreateCompetitionTeam(createCompetitionTeamDTOList);
        //批量启动容器
        containerService.batchStartContainer(containerIdList.toArray(new String[0]));
        QueryCompetitionDetailInfoDTO competitionDetailInfoDTO = queryCompetitionDetailInfo(dto.getUnCode());
        //获取赛题信息
        QueryCompetitionQuestionDetailInfoDTO competitionQuestionDetailInfoDTO = competitionQuestionService.queryCompetitionQuestionDetailInfo(competitionDetailInfoDTO.getCompetitionQuestionUnCode());
        //往容器里添加题目文件
        batchAddCompetitionQuestionToContainer(containerIdList, competitionQuestionDetailInfoDTO.getFilePath());
        //向容器执行完命令之后更新赛事状态的回调函数
        CallBack callBack = new CompetitionChangeStatusCallBack(competitionMapper, dto.getUnCode(), UserDetailUtil.getUserDetailInfo());
        //向容器中执行命令
        batchExecCommandInContainer(dto.getUnCode(), containerIdList, callBack);
        //更新赛题状态为已使用
        competitionQuestionService.updateCompetitionQuestionStatus(CompetitionQuestionStatusEnum.USED, competitionDetailInfoDTO.getCompetitionQuestionUnCode());
        //添加定时任务来准备赛事
        //获取corn表达式
        String corn = CornUtil.getTimeCornFormatStr(competitionDetailInfoDTO.getStartTime());
        //构建赛事启动所需参数dto
        CompetitionStartSchedulerTaskDTO compStartSchedulerTaskDTO = new CompetitionStartSchedulerTaskDTO();
        compStartSchedulerTaskDTO.setUnCode(dto.getUnCode());
        compStartSchedulerTaskDTO.setCompetitionUnCode(dto.getUnCode());
        compStartSchedulerTaskDTO.setRoundCount(queryCompetitionDetailInfo.getRoundCount());
        //序列化赛事启动参数
        ObjectMapper objectMapper = new ObjectMapper();
        String param;
        try {
            param = objectMapper.writeValueAsString(compStartSchedulerTaskDTO);
        } catch (JsonProcessingException e) {
            log.error("赛事启动所需参数序列化失败，失败详情："+e);
            throw new BusinessException(CompetitionResCodeEnum.RC_ERROR_SERIALIZE_PARAM);
        }
        //构建创建定时任务参数dto
        CreateSchedulerTaskDTO createSchedulerTaskDTO = new CreateSchedulerTaskDTO();
        createSchedulerTaskDTO.setUnCode(dto.getUnCode());
        createSchedulerTaskDTO.setBeanName("CompetitionStartSchedulerTask");
        createSchedulerTaskDTO.setMethodName("startCompetitionPreparingTask");
        createSchedulerTaskDTO.setMethodParams(param);
        createSchedulerTaskDTO.setCronExpression(corn);
        createSchedulerTaskDTO.setTaskStatus(EnabledStatusFlagEnum.ENABLED);
        //创建定时任务
        schedulerTaskService.createSchedulerTask(createSchedulerTaskDTO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean createCompetition(CreateCompetitionDTO dto) {
        UserDetailInfoDTO userDetailInfo = UserDetailUtil.getUserDetailInfo();
        CompetitionPO competitionPO = new CompetitionPO();
        competitionPO.setName(dto.getName());
        competitionPO.setCompetitionQuestionUnCode(dto.getCompetitionQuestionUnCode());
        competitionPO.setStartTime(dto.getStartTime());
        competitionPO.setEndTime(dto.getEndTime());
        competitionPO.setRegistrationStartTime(dto.getRegistrationStartTime());
        competitionPO.setRegistrationEndTime(dto.getRegistrationEndTime());
        competitionPO.setStatusFlag(CompetitionStatusEnum.CREATED);
        competitionPO.setRoundCount(dto.getRoundCount());
        competitionPO.setRoundDuration(dto.getRoundDuration());
        competitionPO.setInitialTotalScore(dto.getInitialTotalScore());
        competitionPO.setScorePerAttack(dto.getScorePerAttack());
        competitionPO.setUnCode(UUIDUtil.getUUID());
        competitionPO.setCreateBy(userDetailInfo.getAccount());
        competitionPO.setCreateTime(new Date());
        competitionPO.setUpdateBy(userDetailInfo.getAccount());
        competitionPO.setUpdateTime(new Date());
        competitionPO.setDelFlag(DelFlagEnum.NOT_DEL_FLAG.getFlag());
        try {
            competitionMapper.insert(competitionPO);
        } catch (Exception e) {
            throw new BusinessException(CompetitionResCodeEnum.RC_ERROR_CREATE);
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateCompetition(UpdateCompetitionDTO dto) {
        UserDetailInfoDTO userDetailInfo = UserDetailUtil.getUserDetailInfo();
        //先判断状态
        LambdaQueryWrapper<CompetitionPO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CompetitionPO::getUnCode, dto.getUnCode());
        CompetitionPO competitionPO = competitionMapper.selectOne(queryWrapper);
        if (Objects.isNull(competitionPO)) {
            throw new BusinessException(CompetitionResCodeEnum.RC_COMPETITION_NOT_EXIST);
        }
        //根据状态得出那些字段允许更新
        boolean enableUpdateName = false;
        boolean enableUpdateCompetitionQuestionUnCode = false;
        boolean enableUpdateStartTime = false;
        boolean enableUpdateEndTime = false;
        boolean enableUpdateRegistrationStartTime = false;
        boolean enableUpdateRegistrationEndTime = false;
        boolean enableUpdateRoundsCount = false;
        boolean enableUpdateRoundDuration = false;
        boolean enableUpdateInitialTotalScore = false;
        boolean enableUpdateScorePerAttack = false;
        boolean enableUpdateStatusFlag = false;
        if (competitionPO.getStatusFlag().equals(CompetitionStatusEnum.CREATED)) {
            enableUpdateName = true;
            enableUpdateCompetitionQuestionUnCode = true;
            enableUpdateStartTime = true;
            enableUpdateEndTime = true;
            enableUpdateRoundsCount = true;
            enableUpdateRoundDuration = true;
            enableUpdateInitialTotalScore = true;
            enableUpdateScorePerAttack = true;
        } else if (competitionPO.getStatusFlag().equals(CompetitionStatusEnum.INITIALIZED)
                || competitionPO.getStatusFlag().equals(CompetitionStatusEnum.INITIALIZING)
                || competitionPO.getStatusFlag().equals(CompetitionStatusEnum.READY_FOR_COMP)) {
            enableUpdateName = true;
            enableUpdateStartTime = true;
            enableUpdateEndTime = true;
            enableUpdateRoundsCount = true;
            enableUpdateRoundDuration = true;
        } else if (competitionPO.getStatusFlag().equals(CompetitionStatusEnum.IN_THE_COMP)) {
            enableUpdateName = true;
            enableUpdateRoundsCount = true;
            enableUpdateRoundDuration = true;
            if (dto.getStatusFlag().equals(CompetitionStatusEnum.PAUSE)) {
                //TODO 暂停比赛
            } else if (dto.getStatusFlag().equals(CompetitionStatusEnum.END_THE_COMP)) {
                //TODO 结束比赛
            }
        }
        LambdaUpdateWrapper<CompetitionPO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(CompetitionPO::getUnCode, dto.getUnCode())
                .set(enableUpdateName, CompetitionPO::getName, dto.getName())
                .set(enableUpdateCompetitionQuestionUnCode, CompetitionPO::getCompetitionQuestionUnCode, dto.getCompetitionQuestionUnCode())
                .set(enableUpdateStartTime, CompetitionPO::getStartTime, dto.getStartTime())
                .set(enableUpdateEndTime, CompetitionPO::getEndTime, dto.getEndTime())
                .set(enableUpdateRegistrationStartTime, CompetitionPO::getRegistrationStartTime, dto.getRegistrationStartTime())
                .set(enableUpdateRegistrationEndTime, CompetitionPO::getRegistrationEndTime, dto.getRegistrationEndTime())
                .set(enableUpdateRoundsCount, CompetitionPO::getRoundCount, dto.getRoundCount())
                .set(enableUpdateRoundDuration, CompetitionPO::getRoundDuration, dto.getRoundDuration())
                .set(enableUpdateInitialTotalScore, CompetitionPO::getInitialTotalScore, dto.getInitialTotalScore())
                .set(enableUpdateScorePerAttack, CompetitionPO::getScorePerAttack, dto.getScorePerAttack())
                .set(CompetitionPO::getUpdateBy, userDetailInfo.getAccount())
                .set(CompetitionPO::getUpdateTime, new Date());
        try {
            competitionMapper.update(null, updateWrapper);
        } catch (Exception e) {
            throw new BusinessException(CompetitionResCodeEnum.RC_ERROR_UPDATE);
        }
        return true;
    }

    @Override
    public QueryCompetitionDetailInfoDTO queryCompetitionDetailInfo(String unCode) {
        LambdaQueryWrapper<CompetitionPO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CompetitionPO::getUnCode, unCode)
                .select(CompetitionPO::getUnCode,
                        CompetitionPO::getName,
                        CompetitionPO::getCompetitionQuestionUnCode,
                        CompetitionPO::getStartTime,
                        CompetitionPO::getEndTime,
                        CompetitionPO::getRegistrationStartTime,
                        CompetitionPO::getRegistrationEndTime,
                        CompetitionPO::getStatusFlag,
                        CompetitionPO::getRoundCount,
                        CompetitionPO::getRoundDuration,
                        CompetitionPO::getCurrentRoundCount,
                        CompetitionPO::getInitialTotalScore,
                        CompetitionPO::getScorePerAttack);
        CompetitionPO competitionPO = null;
        try {
            competitionPO = competitionMapper.selectOne(queryWrapper);
        } catch (Exception e) {
            throw new BusinessException(CompetitionResCodeEnum.RC_ERROR_QUERY);
        }
        if (Objects.isNull(competitionPO)) {
            throw new BusinessException(CompetitionResCodeEnum.RC_COMPETITION_NOT_EXIST);
        }
        QueryCompetitionDetailInfoDTO competitionDetailInfoDTO = new QueryCompetitionDetailInfoDTO();
        competitionDetailInfoDTO.setUnCode(competitionPO.getUnCode());
        competitionDetailInfoDTO.setName(competitionPO.getName());
        competitionDetailInfoDTO.setCompetitionQuestionUnCode(competitionPO.getCompetitionQuestionUnCode());
        competitionDetailInfoDTO.setStartTime(competitionPO.getStartTime());
        competitionDetailInfoDTO.setEndTime(competitionPO.getEndTime());
        competitionDetailInfoDTO.setRegistrationStartTime(competitionPO.getRegistrationStartTime());
        competitionDetailInfoDTO.setRegistrationEndTime(competitionPO.getRegistrationEndTime());
        competitionDetailInfoDTO.setStatusFlag(competitionPO.getStatusFlag());
        competitionDetailInfoDTO.setRoundCount(competitionPO.getRoundCount());
        competitionDetailInfoDTO.setRoundDuration(competitionPO.getRoundDuration());
        competitionDetailInfoDTO.setCurrentRoundCount(competitionPO.getCurrentRoundCount());
        competitionDetailInfoDTO.setInitialTotalScore(competitionPO.getInitialTotalScore());
        competitionDetailInfoDTO.setScorePerAttack(competitionPO.getScorePerAttack());
        return competitionDetailInfoDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateCompetitionStatus(String unCode, CompetitionStatusEnum statusFlag) {
        if (Objects.isNull(unCode)) {
            throw new BusinessException(CompetitionResCodeEnum.RC_COMPETITION_NOT_EXIST);
        }
        LambdaUpdateWrapper<CompetitionPO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(CompetitionPO::getUnCode, unCode)
                .set(CompetitionPO::getStatusFlag, statusFlag)
                .set(CompetitionPO::getUpdateBy, UserDetailUtil.getUserDetailInfo().getAccount())
                .set(CompetitionPO::getUpdateTime, new Date());
        try {
            competitionMapper.update(null, updateWrapper);
            return true;
        } catch (Exception e) {
            throw new BusinessException(CompetitionResCodeEnum.RC_ERROR_UPDATE_STATUS);
        }
    }

    @Override
    public Map<String, String> queryCompetitionRoughInfoMap() {
        LambdaQueryWrapper<CompetitionPO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(CompetitionPO::getUnCode, CompetitionPO::getName);
        try {
            List<CompetitionPO> competitionPOList = competitionMapper.selectList(queryWrapper);
            if (Objects.isNull(competitionPOList)) {
                return Map.of();
            }
            Map<String, String> competitionRoughInfoMap = new HashMap<>();
            competitionPOList.forEach(competitionPO -> {
                competitionRoughInfoMap.put(competitionPO.getUnCode(), competitionPO.getName());
            });
            return competitionRoughInfoMap;
        } catch (Exception e) {
            throw new BusinessException(CompetitionResCodeEnum.RC_ERROR_QUERY);
        }
    }

    @Override
    public Page<PaginationQueryCompetitionInfoListVO> paginationQueryCompetitionInfoList(PaginationQueryCompetitionInfoListDTO dto) {
        Page<PaginationQueryCompetitionInfoListVO> paginationQueryCompetitionInfoListVO = new Page<>();
        Page<CompetitionPO> page = new Page<>(dto.getCurrent(), dto.getPageSize());
        LambdaQueryWrapper<CompetitionPO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.isNotBlank(dto.getContext()), CompetitionPO::getName, dto.getContext())
                .orderByDesc(CompetitionPO::getUpdateTime);
        try {
            Page<CompetitionPO> competitionPOPage = competitionMapper.selectPage(page, queryWrapper);
            if (Objects.isNull(competitionPOPage)) {
                return paginationQueryCompetitionInfoListVO;
            }
            List<PaginationQueryCompetitionInfoListVO> competitionInfoListVOList = new ArrayList<>();
            Map<String, String> competitionQuestionRoughInfoMap = competitionQuestionService.queryCompetitionQuestionRoughInfoMap();
            competitionPOPage.getRecords().forEach(competitionPO -> {
                PaginationQueryCompetitionInfoListVO vo = new PaginationQueryCompetitionInfoListVO();
                vo.setUnCode(competitionPO.getUnCode());
                vo.setName(competitionPO.getName());
                vo.setCompetitionQuestionUnCode(competitionPO.getCompetitionQuestionUnCode());
                vo.setCompetitionQuestionName(competitionQuestionRoughInfoMap.get(competitionPO.getCompetitionQuestionUnCode()));
                vo.setStartTime(competitionPO.getStartTime());
                vo.setEndTime(competitionPO.getEndTime());
                vo.setRegistrationStartTime(competitionPO.getRegistrationStartTime());
                vo.setRegistrationEndTime(competitionPO.getRegistrationEndTime());
                vo.setRoundCount(competitionPO.getRoundCount());
                vo.setRoundDuration(competitionPO.getRoundDuration());
                vo.setCurrentRoundCount(competitionPO.getCurrentRoundCount());
                vo.setInitialTotalScore(competitionPO.getInitialTotalScore());
                vo.setScorePerAttack(competitionPO.getScorePerAttack());
                vo.setCreateBy(competitionPO.getCreateBy());
                vo.setCreateTime(competitionPO.getCreateTime());
                vo.setUpdateBy(competitionPO.getUpdateBy());
                vo.setUpdateTime(competitionPO.getUpdateTime());
                vo.setStatusFlag(competitionPO.getStatusFlag());
                competitionInfoListVOList.add(vo);
            });
            paginationQueryCompetitionInfoListVO.setRecords(competitionInfoListVOList);
            paginationQueryCompetitionInfoListVO.setCurrent(competitionPOPage.getCurrent());
            paginationQueryCompetitionInfoListVO.setPages(competitionPOPage.getPages());
            paginationQueryCompetitionInfoListVO.setSize(competitionPOPage.getSize());
            paginationQueryCompetitionInfoListVO.setTotal(competitionPOPage.getTotal());
            return paginationQueryCompetitionInfoListVO;
        } catch (Exception e) {
            throw new BusinessException(CompetitionResCodeEnum.RC_ERROR_QUERY);
        }
    }

    @Override
    public List<QueryCompetitionRoughInfoVO> queryCompetitionRoughInfoList() {
        LambdaQueryWrapper<CompetitionPO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(CompetitionPO::getUnCode, CompetitionPO::getName, CompetitionPO::getStatusFlag);
        try {
            List<QueryCompetitionRoughInfoVO> competitionRoughInfoVOList = new ArrayList<>();
            List<CompetitionPO> competitionPOList = competitionMapper.selectList(queryWrapper);
            if (Objects.isNull(competitionPOList)) {
                return competitionRoughInfoVOList;
            }
            competitionPOList.forEach(competitionPO -> {
                QueryCompetitionRoughInfoVO vo = new QueryCompetitionRoughInfoVO();
                vo.setUnCode(competitionPO.getUnCode());
                vo.setName(competitionPO.getName());
                vo.setStatusFlag(competitionPO.getStatusFlag());
                competitionRoughInfoVOList.add(vo);
            });
            return competitionRoughInfoVOList;
        } catch (Exception e) {
            throw new BusinessException(CompetitionResCodeEnum.RC_ERROR_QUERY);
        }
    }

    @Override
    public QueryCompetitionDetailInfoVO queryCompetitionDetailInfoVO(String unCode) {
        if (StringUtils.isBlank(unCode)) {
            throw new BusinessException(CompetitionResCodeEnum.RC_COMPETITION_NOT_EXIST);
        }
        LambdaQueryWrapper<CompetitionPO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CompetitionPO::getUnCode, unCode)
                .select(CompetitionPO::getUnCode,
                        CompetitionPO::getName,
                        CompetitionPO::getStatusFlag
                );
        try {
            CompetitionPO competitionPO = competitionMapper.selectOne(queryWrapper);
            if (Objects.isNull(competitionPO)) {
                throw new BusinessException(CompetitionResCodeEnum.RC_COMPETITION_NOT_EXIST);
            }
            QueryCompetitionDetailInfoVO vo = new QueryCompetitionDetailInfoVO();
            vo.setUnCode(competitionPO.getUnCode());
            vo.setName(competitionPO.getName());
            vo.setStatusFlag(competitionPO.getStatusFlag());
            return vo;
        } catch (Exception e) {
            throw new BusinessException(CompetitionResCodeEnum.RC_ERROR_QUERY);
        }
    }

    @Override
    public String queryCompetitionNameByUnCode(String unCode) {
        if (StringUtils.isBlank(unCode)) {
            throw new BusinessException(CompetitionResCodeEnum.RC_COMPETITION_NOT_EXIST);
        }
        LambdaQueryWrapper<CompetitionPO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CompetitionPO::getUnCode, unCode)
                .select(CompetitionPO::getName);
        try {
            CompetitionPO competitionPO = competitionMapper.selectOne(queryWrapper);
            if (Objects.isNull(competitionPO)){
                throw new BusinessException(CompetitionResCodeEnum.RC_COMPETITION_NOT_EXIST);
            }
            return competitionPO.getName();
        } catch (Exception e) {
            throw new BusinessException(CompetitionResCodeEnum.RC_ERROR_QUERY);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateCompetitionCurrentRoundCount(String unCode) {
        if (StringUtils.isBlank(unCode)) {
            return;
        }
        //先查询当前赛事的当前回合数
        LambdaQueryWrapper<CompetitionPO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CompetitionPO::getUnCode, unCode)
                .select(CompetitionPO::getUnCode,CompetitionPO::getCurrentRoundCount);
        try {
            CompetitionPO competitionPO = competitionMapper.selectOne(queryWrapper);
            if (Objects.isNull(competitionPO)) {
                throw new BusinessException(CompetitionResCodeEnum.RC_COMPETITION_NOT_EXIST);
            }
            //判断当前赛事的当前回合数是否为空，如果为空，则将当前回合数设置为0
            if(Objects.isNull(competitionPO.getCurrentRoundCount())){
                competitionPO.setCurrentRoundCount(0);
            }
            //更新当前赛事的当前回合数
            LambdaUpdateWrapper<CompetitionPO> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(CompetitionPO::getUnCode, unCode)
                    .set(CompetitionPO::getCurrentRoundCount, competitionPO.getCurrentRoundCount() + 1);
            competitionMapper.update(null, updateWrapper);
        } catch (Exception e) {
            throw new BusinessException(CompetitionResCodeEnum.RC_ERROR_UPDATE_CURRENT_ROUND_COUNT);
        }

    }

    @Override
    public Map<String, String> queryCompetitionUnCodeNameMapByContext(String context) {
        if (StringUtils.isBlank(context)) {
            return Map.of();
        }
        LambdaQueryWrapper<CompetitionPO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.isNotBlank(context), CompetitionPO::getName, context)
                .select(CompetitionPO::getUnCode, CompetitionPO::getName);
        try {
            List<CompetitionPO> competitionPOList = competitionMapper.selectList(queryWrapper);
            if (Objects.isNull(competitionPOList)) {
                return Map.of();
            }
            return competitionPOList.stream().collect(Collectors.toMap(CompetitionPO::getUnCode, CompetitionPO::getName));
        } catch (Exception e) {
            throw new BusinessException(CompetitionResCodeEnum.RC_ERROR_QUERY);
        }
    }

    /**
     * @param containerIdList  容器id列表
     * @param sourceFilePath 赛题文件路径
     * @description: 批量将赛事题目添加到容器中
     */
    private void batchAddCompetitionQuestionToContainer(List<String> containerIdList, String sourceFilePath) {
        containerService.batchCopyFileToContainer(containerIdList.toArray(new String[0]), sourceFilePath, "/");
    }

    /**
     * @param competitionUnCode 赛事业务主键
     * @param containerIdList 容器id列表
     * @description: 批量执行赛题初始化命令至容器中
     */
    private void batchExecCommandInContainer(String competitionUnCode,List<String> containerIdList, CallBack callback) {
        StringBuffer command = new StringBuffer();
        //换源
        command.append("sed -i s@/archive.ubuntu.com/@/mirrors.aliyun.com/@g /etc/apt/sources.list;");
        //移除默认的apache数据
        command.append("rm /var/www/html/index.html && rm /var/www/html/phpinfo.php && chown www-data:www-data /var/www/html -R;");
        //复制资源至指定目录
        command.append("cp -r ./source/* /var/www/html;");
        command.append("cp ./flag.sh /tmp;");
        command.append("cp ./pass.sh /tmp;");
        command.append("cp ./run.sh /tmp;");
        //为资源文件设置权限
        command.append("chmod 700 /tmp/run.sh /tmp/pass.sh /tmp/flag.sh;");
        //添加新用户
        command.append("useradd -s /bin/bash -m -d /home/ctf ctf;");
        command.append("useradd -s /bin/bash -m -d /home/%s %s;");
        //设置新用户密码
        command.append("echo %s:%s | chpasswd;");
        //执行启动脚本
        command.append("bash /tmp/run.sh;");
        List<UpdateCompTeamLoginInfoDTO> compTeamLoginInfoDTOList = new ArrayList<>();
        //遍历容器id列表
        for (int i = 0; i < containerIdList.size(); i++){
            //队伍密码
            String teamAccount = "team" + i;
            //生成队伍密码
            //TODO 给密码加密，要求需要能够解密
            String teamPassword = UUIDUtil.getUUID();
            //构建dto
            UpdateCompTeamLoginInfoDTO dto = new UpdateCompTeamLoginInfoDTO();
            dto.setCompetitionUnCode(competitionUnCode);
            dto.setContainerId(containerIdList.get(i));
            dto.setTeamAccount(teamAccount);
            dto.setTeamPassword(teamPassword);
            compTeamLoginInfoDTOList.add(dto);

            //构建命令
            String commandStr = String.format(command.toString(), teamAccount, teamAccount, teamAccount, teamPassword);
            //执行命令
            containerService.execCommandInContainer(containerIdList.get(i), commandStr, callback);
        }
        //批量更新队伍登录信息
        competitionTeamService.batchUpdateCompetitionTeamLoginInfo(compTeamLoginInfoDTOList);
    }
}
